/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package puente;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;

/**
 * Algoritmo que permite cruzar el puente a 4 personas de forma que se optimize
 * el costo total de cruzar el río
 * 
 * @author Edison Xavier Espinosa Luna
 * @author Luis Alberto Flores Aguilar
 * @author Daniel Jimenez Gonzalez
 * @author Ana Maria Gonzalez Bustan
 * @author Tania Valarezo Cevallos
 */

/*
 * Esta Clase Persona va a tener los atributos de nombre y valor....
 * nombre: A,B,C,D   valor= tiempo que se demora en cruzar el puente (1,2,5,10) 
 */
public class Persona {

    String nombre;
    int valor;
    /*
     * estas variables serviran para almacenar los diferentes 
     * cálculos que se realizan
     */
    //tiempo menor en cruzar el puente
    int tiempoMenor;
    // tiempo mayor en cruzar el puente
    int tiempoMayor;
    // variables para hacer calculos
    int rango;
    int indice;
    // tiempo total que se demoran en cruzar el puente
    int tiempoTotal;
    // archivo almacena toda la presentación
    public static String archivo = "";

    public void setTiempoTotal(int tiempoTotal) {
        this.tiempoTotal = tiempoTotal;
    }

    public int getTiempoTotal() {
        return tiempoTotal;
    }
    //variables auxiliares
    Persona auxiliar1;
    Persona auxiliar2;
    // orilla1 almacena a las personas que estan en un lado del puente
    //inicialmente esta llena con A B C D
    ArrayList<Persona> orilla1 = new ArrayList<Persona>();
    // orilla2 almacena a las personas que estan en el otro lado del puente
    // inicialmente vacia
    ArrayList<Persona> orilla2 = new ArrayList<Persona>();

    public String getNombre() {
        return nombre;
    }

    public void setNombre(String nombre) {
        this.nombre = nombre;
    }

    public int getValor() {
        return valor;
    }

    public void setValor(int valor) {
        this.valor = valor;
    }
    /*
     * Este metodo pricipal() es el encargado de ejecutar 
     * los demas metodos existentes en la clase
     */

    public void principal() {
        cruzarRio();
        archivo += "\r\n\r\niteracion 1" + "\r\n" + "cruzan: " + orilla2.get(0).getNombre() + orilla2.get(1).getNombre() + "\r\n"
                + "permanecen : " + orilla1.get(0).getNombre() + orilla1.get(1).getNombre() + "\r\n";
        System.out.println("iteracion 1");

        System.out.println("cruzan: " + orilla2.get(0).getNombre() + orilla2.get(1).getNombre());
        System.out.println("permanecen : " + orilla1.get(0).getNombre() + orilla1.get(1).getNombre());
        archivo += "iteración 2 \r\n";
        System.out.println("iteracion 2");
        primerRetorno(orilla2.get(0), orilla2.get(1));
        archivo += "iteracion 3 \r\n";
        System.out.println("iteracion 3");
        cruzarRio();
        archivo += "cruzan: " + orilla2.get(1).getNombre() + orilla2.get(2).getNombre() + "\r\n"
                + "se queda : " + orilla1.get(0).getNombre() + "\r\n";
        System.out.println("cruzan: " + orilla2.get(1).getNombre() + orilla2.get(2).getNombre());
        System.out.println("se queda : " + orilla1.get(0).getNombre());
        archivo += "iteracion 4 \r\n";
        System.out.println("iteracion 4");
        segundoRetorno(orilla2.get(0), orilla2.get(1), orilla2.get(2));
        archivo += "iteracion 5 \r\n";
        System.out.println("iteracion 5");
        cruzarRio();
        archivo += "cruzan: " + orilla2.get(2).getNombre() + orilla2.get(3).getNombre() + "\r\n"
                + "Todos están en el otro lado del puente" + "\r\n"
                + "El tiempo que emplearon en total fue: " + tiempoTotal + " segundos" + "\r\n";
        System.out.println("cruzan: " + orilla2.get(2).getNombre() + orilla2.get(3).getNombre());
        System.out.println("Todos están en el otro lado del puente");
        System.out.println("El tiempo que emplearon en total fue: " + tiempoTotal + " segundos");

    }
    /*
     * Metodo cruzarRio() selecciona aleatoriamente independientemente del 
     * valor dos personas de orilla1 para cruzar(agregar) a orilla2
     * Luego a las personas seleccionadas las elimina momentaneamente de
     * orilla1
     */

    public void cruzarRio() {
        indice = (int) (Math.random() * generarRango());
        auxiliar1 = orilla1.get(indice);
        orilla2.add(auxiliar1);
        orilla1.remove(indice);
        rango = rango - 1;
        indice = (int) (Math.random() * generarRango());
        auxiliar2 = orilla1.get(indice);
        orilla2.add(auxiliar2);
        orilla1.remove(indice);
        tiempoTotal += tiempoMayor(auxiliar1, auxiliar2);
    }
    /*
     * generarRango() obtiene un valor entero dependiendo
     * del tamaño de orilla1, para luego ser usado en el metodo anterior
     */

    public int generarRango() {
        return rango = orilla1.size();
    }

    /*
     * primerRetorno() selecciona a la persona de orilla2 con menor valor para que
     * regrese a orilla1 y seguir acumulando el costo total de cruzar el puente, todo esto
     * despues de la primera cruzada.
     */
    public void primerRetorno(Persona a, Persona b) {
        if (a.getValor() <= b.getValor()) {
            orilla1.add(a);
            orilla2.remove(a);
            tiempoTotal += tiempoMenor(a, b);
            archivo += "regresa : " + orilla1.get(2).getNombre() + "\r\n" + "se queda : " + orilla2.get(0).getNombre() + "\r\n";
            System.out.println("regresa : " + orilla1.get(2).getNombre());
            System.out.println("se queda : " + orilla2.get(0).getNombre());
        } else {
            orilla1.add(b);
            orilla2.remove(b);
            tiempoTotal += tiempoMenor(a, b);
            archivo += "regresa : " + orilla1.get(2).getNombre() + "\r\n" + "se queda : " + orilla2.get(0).getNombre() + "\r\n";
            System.out.println("regresa : " + orilla1.get(2).getNombre());
            System.out.println("se queda : " + orilla2.get(0).getNombre());
        }
    }
    /*
     * segundoRetorno() selecciona a la persona de orilla2 con menor valor para que
     * regrese a orilla1 y seguir acumulando el costo total de cruzar el puente, todo esto
     * despues de la segunda cruzada.
     */

    public void segundoRetorno(Persona a, Persona b, Persona c) {
        if (a.getValor() <= b.getValor()) {
            if (a.getValor() <= c.getValor()) {
                orilla1.add(a);
                orilla2.remove(a);
                archivo += "regresa : " + orilla1.get(1).getNombre() + "\r\n" + "se quedan: "
                        + orilla2.get(0).getNombre() + orilla2.get(1).getNombre() + "\r\n";
                System.out.println("regresa : " + orilla1.get(1).getNombre());
                System.out.println("se quedan: " + orilla2.get(0).getNombre() + orilla2.get(1).getNombre());
                tiempoTotal += tiempoMenor(a, b);
            } else {
                orilla1.add(c);
                orilla2.remove(c);
                archivo += "regresa : " + orilla1.get(1).getNombre() + "\r\n" + "se quedan: " + orilla2.get(0).getNombre()
                        + orilla2.get(1).getNombre() + "\r\n";
                System.out.println("regresa : " + orilla1.get(1).getNombre());
                System.out.println("se quedan: " + orilla2.get(0).getNombre() + orilla2.get(1).getNombre());
                tiempoTotal += tiempoMenor(a, b);
            }

        } else {
            orilla1.add(b);
            orilla2.remove(b);
            archivo += "regresa : " + orilla1.get(1).getNombre() + "\r\n" + "se quedan: " + orilla2.get(0).getNombre()
                    + orilla2.get(1).getNombre() + "\r\n";
            System.out.println("regresa : " + orilla1.get(1).getNombre());
            System.out.println("se quedan: " + orilla2.get(0).getNombre()
                    + orilla2.get(1).getNombre());
            tiempoTotal += tiempoMenor(a, b);
        }
    }

    // añadirElementos() agrega las personas a la orilla1
    public void añadirElementos(Persona a, Persona b, Persona c, Persona d) {
        orilla1.add(a);
        orilla1.add(b);
        orilla1.add(c);
        orilla1.add(d);
    }
    /*
     * tiempoMenor() calcula el menor tiempo de 2 personas cuando estan en orilla 2
     * para poder seleccionar cual será la persona que regresa a orilla1 con el menor
     * tiempo de los dos.
     */

    public int tiempoMenor(Persona a, Persona b) {
        if (a.getValor() <= b.getValor()) {
            tiempoMenor = a.getValor();
        } else {
            tiempoMenor = b.getValor();
        }
        return tiempoMenor;
    }
    /*
     * tiempoMayor() calcula el mayor tiempo de 2 personas cuando estan en orilla 1 y
     * poder acumular el costo total de cruzar a orilla2.
     */

    public int tiempoMayor(Persona a, Persona b) {
        if (a.getValor() >= b.getValor()) {
            tiempoMayor = a.getValor();
        } else {
            tiempoMayor = b.getValor();
        }
        return tiempoMayor;
    }

    /*
     * main() llama a todos los metodos para que se ejecuten 
     */
    public static void main(String[] args) throws IOException {
        // TODO code application logic here

        Persona a = new Persona();
        a.setNombre("A");
        a.setValor(1);

        Persona b = new Persona();
        b.setNombre("B");
        b.setValor(1);

        Persona c = new Persona();
        c.setNombre("C");
        c.setValor(1);

        Persona d = new Persona();
        d.setNombre("D");
        d.setValor(1);

        //**********calcula tiempo de ejecución**********//
        // calcula tiempo en nanosegundos
        long tiempoInicio = System.nanoTime();
        // agrega elementos
        a.añadirElementos(a, b, c, d);
        ArrayList<Integer> tiempo = new ArrayList<Integer>();
        int contador = 0;
        //calcula tiempo de ejecución y llama al metodo pricipal() para que realice
        // todos los procesos.
        while (contador <= 1) {
            if (tiempo.isEmpty()) {
                long totalTiempo = System.nanoTime() - tiempoInicio;
                a.principal();
                tiempo.add(a.getTiempoTotal());
                contador++;
                archivo += "El tiempo de demora es :" + totalTiempo + " nanosegundos \r\n\r\n\r\n";
                tiempo.add(a.getTiempoTotal());
                /*
                 * BufferedWritter crea un archivo txt para almacenar las iteraciones de las personas 
                 * para cruzar el puente.
                 */
                BufferedWriter bw = new BufferedWriter(new FileWriter("C:\\Users\\Daniel\\Desktop\\cruzar.txt", true));
                // escribe en el archivo txt
                bw.write(archivo);
                bw.close();
            } else {
                archivo = "";
                a.setTiempoTotal(0);
                a.orilla1.removeAll(a.orilla1);
                a.orilla2.removeAll(a.orilla2);
                a.añadirElementos(a, b, c, d);
                a.principal();
                long totalTiempo = System.nanoTime() - tiempoInicio;
                archivo += "El tiempo de demora es :" + totalTiempo + " nanosegundos \r\n\r\n\r\n";
                if (!tiempo.contains(a.getTiempoTotal())) {
                    tiempo.add(a.getTiempoTotal());
                    contador++;
                    BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\Mis documentos\\cruzar.txt", true));
                    bw.write(archivo);
                    bw.close();
                }
            }
        }
        //**********calcula tiempo de ejecucion**********//

        //******** 
        //calcula el menor y mayor costo total de cruce
        // de varias iteraciones
        int mayor = 0;
        int menor = 0;
        menor = tiempo.get(0);
        mayor = tiempo.get(0);
        for (Integer variable : tiempo) {
            if (variable < menor) {
                menor = variable;
            }
            if (mayor < variable) {
                mayor = variable;
            }
        }
        archivo = "\r\n\r\nEl costo mínimo es: " + menor + "\r\n\r\nEl costo mayor es: " + mayor;
        BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\Mis documentos\\cruzar.txt", true));
        bw.write(archivo);
        bw.close();
    }
}
